/*
 * Copyright (c) 2023 Huawei Technologies Co., Ltd.
 * openUBMC is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *         http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
 * EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
 * MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */

#include "i_chip.h"
#include "bus/bus_base/bus.h"
#include <mc/log.h>

namespace dev {

void Interface_Chip::from_variant(mc::mutable_dict& csr_object) {
    try {
        // 从配置中加载基类属性
        if (csr_object.contains("Address")) {
            this->Address = csr_object.at("Address").as<uint32_t>();
        }
        if (csr_object.contains("OffsetWidth")) {
            this->OffsetWidth = csr_object.at("OffsetWidth").as<uint8_t>();
        }
        if (csr_object.contains("AddrWidth")) {
            this->AddrWidth = csr_object.at("AddrWidth").as<uint8_t>();
        }
        if (csr_object.contains("WriteTmout")) {
            this->WriteTmout = csr_object.at("WriteTmout").as<uint32_t>();
        }
        if (csr_object.contains("ReadTmout")) {
            this->ReadTmout = csr_object.at("ReadTmout").as<uint32_t>();
        }
        if (csr_object.contains("RwBlockSize")) {
            this->RwBlockSize = csr_object.at("RwBlockSize").as<uint8_t>();
        }
        if (csr_object.contains("WriteInterval")) {
            this->WriteInterval = csr_object.at("WriteInterval").as<uint8_t>();
        }
        if (csr_object.contains("ReadInterval")) {
            this->ReadInterval = csr_object.at("ReadInterval").as<uint8_t>();
        }
        if (csr_object.contains("WriteRetryTimes")) {
            this->WriteRetryTimes = csr_object.at("WriteRetryTimes").as<uint8_t>();
        }
        if (csr_object.contains("ReadRetryTimes")) {
            this->ReadRetryTimes = csr_object.at("ReadRetryTimes").as<uint8_t>();
        }
    } catch (const std::exception& e) {
        MC_THROW(mc::parse_error_exception, "Failed to parse chip configuration: ${error}", ("error", e.what()));
    }
}

std::vector<uint8_t> Interface_Chip::BitIORead(uint32_t offset, uint8_t length, uint32_t mask) {
    std::vector<uint8_t> out_buffer(length);
    std::vector<uint8_t> in_buffer;
    BusLock              lock(*m_chip->get_host_bus());
    std::string          error;
    auto                 result = m_chip->bit_read(offset, length, mask, in_buffer, out_buffer, error);

    if (result != HAS_OK) {
        MC_THROW(mc::method_call_exception, "BitIORead failed, result: ${result}, error: ${error}",
                 ("result", result)("error", error));
    }

    return out_buffer;
}

void Interface_Chip::BitIOWrite(uint32_t offset, uint8_t length, uint32_t mask,
                                const std::vector<uint8_t>& buffer) {
    std::vector<uint8_t> out_buffer;
    BusLock              lock(*m_chip->get_host_bus());
    std::string          error;
    auto                 result = m_chip->bit_write(offset, length, mask, buffer, out_buffer, error);

    if (result != HAS_OK) {
        MC_THROW(mc::method_call_exception, "BitIOWrite failed, result: ${result}, error: ${error}",
                 ("result", result)("error", error));
    }
}

std::vector<uint8_t> Interface_Chip::BlockIORead(uint32_t offset, uint32_t length) {
    std::vector<uint8_t> out_buffer(length);
    std::vector<uint8_t> in_buffer;
    BusLock              lock(*m_chip->get_host_bus());
    std::string          error;
    auto                 result = m_chip->block_read(offset, length, in_buffer, out_buffer, error);

    if (result != HAS_OK) {
        MC_THROW(mc::method_call_exception, "BlockIORead failed, result: ${result}, error: ${error}",
                 ("result", result)("error", error));
    }

    return out_buffer;
}

void Interface_Chip::BlockIOWrite(uint32_t offset, const std::vector<uint8_t>& buffer) {
    std::vector<uint8_t> out_buffer;
    BusLock              lock(*m_chip->get_host_bus());
    std::string          error;
    auto                 result = m_chip->block_write(offset, buffer, out_buffer, error);

    if (result != HAS_OK) {
        MC_THROW(mc::method_call_exception, "BlockIOWrite failed, result: ${result}, error: ${error}",
                 ("result", result)("error", error));
    }
}

std::vector<uint8_t> Interface_Chip::BlockIOWriteRead(const std::vector<uint8_t>& indata,
                                                      uint32_t                    read_length) {
    std::vector<uint8_t> out_buffer(read_length);
    BusLock              lock(*m_chip->get_host_bus());
    std::string          error;
    auto result = m_chip->block_write_read(EXTEND_READ_MODE, indata, read_length, out_buffer, error);

    if (result != HAS_OK) {
        MC_THROW(mc::method_call_exception, "BlockIOWriteRead failed, result: ${result}, error: ${error}",
                 ("result", result)("error", error));
    }
    return out_buffer;
}

std::vector<uint8_t> Interface_Chip::BlockIOComboWriteRead(uint32_t                    write_offset,
                                                           const std::vector<uint8_t>& write_buffer,
                                                           uint32_t                    read_offset,
                                                           uint32_t read_length) {
    std::vector<uint8_t> out_buffer(read_length);
    std::vector<uint8_t> in_buffer;
    BusLock              lock(*m_chip->get_host_bus());
    std::string          error;
    auto result = m_chip->combo_block_write_read(write_offset, write_buffer, read_offset,
                                                 read_length, in_buffer, out_buffer, error);

    if (result != HAS_OK) {
        MC_THROW(mc::method_call_exception, "BlockIOComboWriteRead failed, result: ${result}, error: ${error}",
                 ("result", result)("error", error));
    }

    return out_buffer;
}

} // namespace dev

MC_REFLECT(dev::Interface_Chip)
